#ifndef IO_HANDLER_H
#define IO_HANDLER_H

#include <boost/enable_shared_from_this.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/asio.hpp>

#include "i_package.h"
#include "i_io_handler.h"


#define DumpError(stage, err, addr) \
	cout << "error occurred while " << #stage << " on " << \
	addr.address().to_string() << " code:" << err.value() <<  " message" << err.message() << endl

#define DumpCloseDetected(stage, addr) \
	cout << "close detected while " << #stage << " on " << \
	addr.address().to_string() << endl

#define DumpUnKnownPak(h, addr) cout << "unknown Package id: " << h.id_  << " on " << \
	addr.address().to_string() << endl

#define DumpClose(addr) cout << "active close on " << addr.address().to_string() << endl


using boost::asio::ip::tcp;
class IoHandler : public IIoHandler, public boost::enable_shared_from_this<IoHandler>
{
protected:
	tcp::socket socket_;
	boost::asio::io_service& service_;
	tcp::endpoint addr_;

private:
	boost::asio::streambuf sendBuf_;
	boost::asio::streambuf recvBuf_;
	Header curHeader_;
	boost::recursive_mutex sendingMutex_;
	bool closed_;

	void asyncReadHeader();
	void tryReadHeader(const size_t& bytes_transferred, 
		const boost::system::error_code& err);

	void asyncReadPackage();
	void tryReadPackage(const size_t& byte_transferred,
		const boost::system::error_code& err);

	void onWrite(const size_t& byte_transferred,
		const boost::system::error_code& err);

	void _send();
	void _close();
public:
	typedef boost::shared_ptr<IoHandler> Ptr;
	IoHandler(boost::asio::io_service& service) : socket_(service), service_(service),
		closed_(false){}
	virtual ~IoHandler(){}

	tcp::socket& socket() { return socket_; }
	void start();
	void send(IPackage::Ptr package);
	void close();
};

#endif